#include "boot.h"
#include "Lora.h"
#include "Lboard.h"

#define  WAIT_UPDATE_CNT   3            //等待3次升级指令
#define  BOOT_DEBUG       
#define  BOOT_VER          "3.0"

extern uint8_t rf_buffer[255];
extern uint8_t update_type;             //0:app  1:logic
extern uint32_t firmware_length;        //固件长度
extern uint32_t firmware_package_cnt;   //固件总包号
extern uint32_t firmware_crc;           //CRC

static uint32_t apb_clken;
static uint32_t misc_ctrl;

//********************************************************
// 看门狗
// 功能：
// 返回：
//********************************************************
void watchdog_init()
{
   SYS_EnableAPBClock(APB_MASK_WATCHDOG0);
   WDOG_Init(5*SYS_GetPclkFreq()); // 5 second
}


void WDOG_DeInit(void)
{
  SYS_DisableAPBClock(APB_MASK_WATCHDOG0);
  WDOG_UnLock();
  WDOG->WdogControl = 0;
  WDOG_Lock();
}
//********************************************************
// enter_boot()
// 功能：进入升级
// 返回：
//********************************************************
void enter_boot()
{
  boot();
  WDOG_DeInit();

  INT_DisableIntGlobal();
  INT_DisableIntExternal();
  bootEnd();
  UTIL_IdleUs(3000000);
}

//********************************************************
// rf_transmit_reset(void)
// 功能：接收升级指令
// 返回：
//********************************************************
uint8_t rf_transmit_reset(void)
{
   uint8_t length=0;

   rf_buffer[0] = 0xAB;
   rf_buffer[1] = 0x02;
   rf_buffer[2] = 0x77;
   rf_buffer[3] = 0x00;
   rf_transmit(rf_buffer, 4, 2000);     //发送复位成功通知透传板可以进行升级
   UTIL_IdleUs(2000);    //延时
   length=rf_receive(rf_buffer, 2000);  //等待2S升级指令
   if((length>0)&&(rf_buffer[2]==0x7F))
   {
      update_type          = rf_buffer[3];
      firmware_length      = (rf_buffer[4]<<24)  | (rf_buffer[5]<<16)  | (rf_buffer[6]<<8)  | rf_buffer[7];
      firmware_package_cnt = (rf_buffer[8]<<24)  | (rf_buffer[9]<<16)  | (rf_buffer[10]<<8) | rf_buffer[11];
      firmware_crc         = (rf_buffer[12]<<24) | (rf_buffer[13]<<16) | (rf_buffer[14]<<8) | rf_buffer[15];
      if(firmware_length>=0x20000)
      {
          dbg_printf("firmware too long\r\n");
          return 1;
      }
      return 0;
   }

   return 1;
}
//********************************************************
// main()
// 功能：
// 返回：
//********************************************************
int main()
{
  //wait for UPLOAD-sign
  uint32_t pathTo = 0;
  uint64_t startTm = 0;
  uint8_t  ret=1;  
  uint8_t  wait_cnt=0;
  uint32_t *param  = (uint32_t*)(DFU_APP_PARAM);          //固件大小：固件长度：CRC

  /*保存初始配置*/
  apb_clken = SYS->APB_CLKENABLE;
  misc_ctrl = SYS->MISC_CNTL;
  
  /*射频初始化*/
  Lboard_init();
  GPIO_SetHigh(LIGHT_GPIO_Port, RED_LIGHT_PIN|BLUE_LIGHT_PIN);
  UTIL_IdleUs(1000000); 
  GPIO_SetLow(LIGHT_GPIO_Port, RED_LIGHT_PIN|BLUE_LIGHT_PIN);

  watchdog_init();
  #ifdef BOOT_DEBUG
    UTIL_StartLogger();
    dbg_printf("  BOOT");
    dbg_printf("  %s\r\n",BOOT_VER);
    dbg_printf("  Clock Frequency : %dmhz\r\n", SYS_GetSysClkFreq()/1000000);
    dbg_printf("  Option Byte Error %d\r\n", FLASH_IsOptionByteError()); 
    dbg_printf("  Read  Protection %d\r\n", FLASH_IsReadProtected()); 
    dbg_printf("  Write Protection 0x%x\r\n",  FLASH->WRPR);
  #else
  MSG_UART = 0;
  #endif


  WDOG_Feed();
  dbg_printf("sx1280_init()\r\n");

  sx1280_int();
  GPIO_SetHigh(LIGHT_GPIO_Port, RED_LIGHT_PIN);
  UTIL_IdleUs(1000000); 
  GPIO_SetLow(LIGHT_GPIO_Port, RED_LIGHT_PIN);

  WDOG_Feed();
  dbg_printf("delay 3s\r\n");
  UTIL_IdleUs(3000000);    //延时
  
  /*接收升级指令,指令复位或者参数信息没有配置*/
  GPIO_SetHigh(LIGHT_GPIO_Port, RED_LIGHT_PIN);
  while((wait_cnt<WAIT_UPDATE_CNT)||(*param==0xFFFFFFFF))
  { 
    WDOG_Feed();
    ret = rf_transmit_reset();
    UTIL_IdleUs(300000);    //延时
    dbg_printf("wait for update\r\n");
    wait_cnt++;
    if(ret==0)
    {
       pathTo = 1;
       break;
    }
  }
  GPIO_SetLow(LIGHT_GPIO_Port, RED_LIGHT_PIN);

  while(1)
  {
    if (pathTo == 0) //path to app
    {
      WDOG_DeInit();
      dbg_printf("enter app\r\n");
      #ifdef BOOT_DEBUG
      UTIL_StopLogger();
      #endif
      INT_DisableIntGlobal();
      INT_DisableIntExternal();
      SYS_DisableAHBClock(AHB_MASK_DMAC0);

      //reset all state
      SYS->APB_CLKENABLE = apb_clken;
      SYS->MISC_CNTL = misc_ctrl;
      SYS_SwitchHSIClock();
      
      SYS_EnableAPBClock(APB_MASK_FCB0);
      FCB_AutoConfig(DFU_APP_LOGIC_ADDRESS); //restore APP logic
      SYS_DisableAPBClock(APB_MASK_FCB0);

      //jump to app
      GPIO_SetLow(LIGHT_GPIO_Port, BLUE_LIGHT_PIN);
      UTIL_JumpToAddress(DFU_APP_CODE_ADDRESS);
    }
    else //to boot
    {
      GPIO_SetHigh(LIGHT_GPIO_Port, BLUE_LIGHT_PIN);
      dbg_printf("enter boot\r\n");
      enter_boot();
    }
  }

}
